#include "canbusTool.h"
#include "commonDefine.h"


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/can.h>
#include <linux/can/raw.h>


canbusTool::canbusTool(cmdWorker* worker,int devID):
    canbusID(devID),socketCan(-1),parser(worker)
{

}

canbusTool::~canbusTool(){
    canbusClose();
}

int canbusTool::canbusInit(std::string devName){
    
    socketCan = socket(PF_CAN,SOCK_RAW,CAN_RAW);
    if(socketCan < 0){
        ERRO_PRT("socket can device");
        return -1;
    }

    struct ifreq    ifr;// can0 500k
    strcpy(ifr.ifr_ifrn.ifrn_name,devName.c_str());
    int ret = ioctl(socketCan,SIOCGIFINDEX,&ifr);
    if(ret == -1){
        ERRO_PRT("ioctl socketCan SIOCGIFADDR device %s,%d\n",ifr.ifr_ifrn.ifrn_name,errno);
        close(socketCan);
        socketCan = -1;
        return -1;
    }
    
    
    // int txqueuelen = 20;
    // setsockopt(socketCan, SOL_CAN_RAW,SO_SNDBUF, &txqueuelen, sizeof(txqueuelen));

    struct sockaddr_can  addr;
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    ret = bind(socketCan,(const sockaddr*)&addr,sizeof(addr));
    if(ret < 0){
        ERRO_PRT("bind error %d\n",errno);
        close(socketCan);
        socketCan = -1;
        return  -1;
    }

    // 这里还需添加can id 过滤



    // add can socket fd to selectHelper
    SelectHelperV2::INS().FD_SELECT(socketCan,parser);

    return socketCan;
}

 
int canbusTool::canbusSend(const uint8_t* data,int size){

    if (socketCan != -1)
    {
        int offset = 0;
        while (size - offset >= 8)
        {
            struct can_frame cf = {};
            cf.can_id = canbusID;
            cf.can_dlc = 8;
            memcpy(cf.data, data + offset, 8);
            if(CAN_MTU != write(socketCan, &cf, CAN_MTU)){
                ERRO_PRT("error send can frame\n");
                return -1;
            }
            offset +=8;
        }

        if(size - offset > 0){
            struct can_frame cf = {};
            cf.can_id = canbusID;
            cf.can_dlc = size - offset;
            memcpy(cf.data, data + offset, size - offset);
            if (write(socketCan, &cf, CAN_MTU) != CAN_MTU)
            {
                INFO_PRT("error %d\n", errno);
            }
        }
        
        return size;

    }

    return -1;
}

int canbusTool::canbusClose(){
    if(socketCan != -1){

        SelectHelperV2::INS().FD_CANCEL(socketCan);
        close(socketCan);
    }
    return 0;
}

int canbusTool::setFilterOption(int filterID){

    return 0;
}